package frsf.cidisi.exercise.tpidemia.search;

import Interfaz.NewJFrame;
import Interfaz.NewJPanel;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import frsf.cidisi.exercise.tpidemia.entidades.Cofre;
import frsf.cidisi.exercise.tpidemia.entidades.Pair;
import frsf.cidisi.exercise.tpidemia.entidades.PairDist;
import frsf.cidisi.faia.agent.Perception;
import frsf.cidisi.faia.agent.search.SearchBasedAgentState;

/**
 * Represent the internal state of the Agent.
 */
public class ArqueologoState extends SearchBasedAgentState {
    
    
    NewJFrame frame = new NewJFrame();
    NewJPanel j = new NewJPanel();
    private String posicion;
    private  static final double capacidad = 450;
    private HashMap<String, Collection<PairDist>> map;
    private HashMap<String, Cofre> tesoro;
    private double capacidadOcupada;
    private double valorObtenido;
    private ArrayList<String> visitadas1;
    private ArrayList<String> visitadas2;
    private String posicionObjetivo;
    private String posicionPirata;

    public String getPosicionPirata() {
        return posicionPirata;
    }

    public void setPosicionPirata(String posicionPirata) {
        this.posicionPirata = posicionPirata;
    }
	private double distanciaRecorrida;
	
	public static final String Aragaey = "Aragaey";
    public static final String Ase = "Ase";
    public static final String Bresol = "Bresol";
    public static final String Bulovoe = "Bulovoe";
    public static final String Cabe = "Cabe";
    public static final String Cenede = "Cenede";
    public static final String Ergintone = "Ergintone";
    public static final String Icaedur = "Icaedur";
    public static final String Mixocu = "Mixocu";
    public static final String Peregaey = "Peregaey";
    public static final String Vinizaile = "Vinizaile";

	public ArqueologoState() {
    
    	this.map = new HashMap<String, Collection<PairDist>>();
    	this.tesoro = new HashMap<String, Cofre>();
    	this.visitadas1 = new ArrayList<String>();
    	this.visitadas2 = new ArrayList<String>();
    	//visitadas1.add(this.posicion);
    	//this.posicionObjetivo = Bulovoe;
        this.initState();
    }
	

    /**
     * This method clones the state of the agent. It's used in the search
     * process, when creating the search tree.
     */
    @Override
    public ArqueologoState clone() {
        
        ArrayList<String> vis1 = new ArrayList<String>();
        vis1.addAll(visitadas1);
        ArrayList<String> vis2 = new ArrayList<String>();
        vis2.addAll(visitadas2);
        HashMap<String, Collection<PairDist>> mapa =new HashMap<String, Collection<PairDist>>();
        mapa.putAll(map);
        //for(String k :map.keySet()){
        	
        //}
        HashMap<String, Cofre> tes =new HashMap<String, Cofre>();
        tes.putAll(tesoro);
        
        
        //HashMap<String, Collection<PairDist>> mapa = (HashMap<String, Collection<PairDist>>) map.clone(); 
        ArqueologoState newState = new ArqueologoState(posicion,mapa,tes,capacidadOcupada, valorObtenido,vis1,vis2,posicionObjetivo, distanciaRecorrida);
        //System.out.println("NewState: "+newState.toString());
        
        return newState;
    }
    private ArqueologoState (String posicion, HashMap<String, Collection<PairDist>> map, HashMap<String, Cofre> tesoro, double capacidadOcupada, double valorObtenido, ArrayList<String> visitadas1, ArrayList<String> visitadas2, String posicionObjetivo, double distanciaRecorrida){
    	super();
    	this.posicion = posicion;
    	this.map = map;
    	this.tesoro = tesoro;
    	this.capacidadOcupada = capacidadOcupada;
    	this.valorObtenido = valorObtenido;
    	this.visitadas1 = visitadas1;
    	this.visitadas2 = visitadas2;
    	this.posicionObjetivo = posicionObjetivo;
    	this.distanciaRecorrida = distanciaRecorrida;
    }

    /**
     * This method is used to update the Agent State when a Perception is
     * received by the Simulator.
     */
    @Override
    public void updateState(Perception p) {
        
        ArqueologoPerception per = (ArqueologoPerception) p;
        this.posicion=per.getGps();
        
//        if(visitadas1.contains(posicion) && !visitadas2.contains(posicion)){
//        	visitadas2.add(posicion);
//        }
//        if(!visitadas1.contains(posicion)){
//        	visitadas1.add(posicion);
//        }
        this.tesoro = per.getSatelite();
        this.posicionPirata = per.getPirata();
        this.tesoro.remove(posicion);
        if(per.getCamara() != null){
        	this.tesoro.put(posicion, per.getCamara());
        }
        ArrayList<String> a = new ArrayList<String>();
        a.add(Ase);
        a.add(Aragaey);
        a.add(Bresol);
        a.add(Bulovoe);
        a.add(Cabe);
        a.add(Cenede);
        a.add(Ergintone);
        a.add(Icaedur);
        a.add(Mixocu);
        a.add(Peregaey);
        a.add(Vinizaile);
//        ArrayList<String> b = new ArrayList<String>();
//        Cofre f;
//        for(String aldea : a){
//            f = new Cofre();
//            f = this.tesoro.get(a);
//            f.CalcularTesoro();
//            if(f.getPeso() != 0){
//                b.add(aldea);
//            }
//        }
        
        //this.frame.actualizar(a,this.getPosicion(),this.getPosicionPirata(),this.getCapacidadOcupada(), this.getValorObtenido());
        this.frame.actualizar(a,this.getPosicion(),this.getPosicionPirata(),this.getCapacidadOcupada(), this.getValorObtenido());
        
//        frame.actualizar(a,per.getGps(),"Cabe",this.getCapacidadOcupada(), this.getValorObtenido());
        frame.setVisible(true);
        
        try{
        Thread.sleep(2000);
        }catch(InterruptedException e){}
        
        	
        
    }

    /**
     * This method is optional, and sets the initial state of the agent.
     */
    @Override
    public void initState() {
        
    	this.posicion = "Aragaey";
    	this.capacidadOcupada = 0;
    	this.valorObtenido = 0;
    	this.distanciaRecorrida = 0;
    	this.posicionObjetivo = Cenede;
    	this.visitadas1 = new ArrayList<String>();
    	this.visitadas1.add(posicion);
    	this.visitadas2 = new ArrayList<String>();
    	this.map = new HashMap<String, Collection<PairDist>>();
    	//this.posicionObjetivo = "Cenede";
    	//Ergintone
    	ArrayList <PairDist> adyacentesErgintone = new ArrayList<PairDist>();
    	PairDist ergintone1 = new PairDist(Bulovoe,200);
    	PairDist ergintone2 = new PairDist(Peregaey,180);
    	PairDist ergintone3 = new PairDist(Aragaey,100);
    	adyacentesErgintone.add(ergintone1);
    	adyacentesErgintone.add(ergintone2);
    	adyacentesErgintone.add(ergintone3);
    	
    	//Bulovoe
    	ArrayList <PairDist> adyacentesBulovoe= new ArrayList<PairDist>();
    	PairDist bulovoe1 = new PairDist(Icaedur,350);
    	PairDist bulovoe2 = new PairDist(Ergintone,200);
    	adyacentesBulovoe.add(bulovoe1);
    	adyacentesBulovoe.add(bulovoe2);
    	
    	//Peregaey
    	ArrayList <PairDist> adyacentesPeregaey = new ArrayList<PairDist>();
    	PairDist paragaey1 = new PairDist(Ergintone,180);
    	PairDist paragaey2 = new PairDist(Vinizaile,450);
    	adyacentesPeregaey.add(paragaey1);
    	adyacentesPeregaey.add(paragaey2);
    	
    	//Aragaey
    	ArrayList <PairDist> adyacentesAragaey= new ArrayList<PairDist>();
    	PairDist aragaey1 = new PairDist(Bresol,150);
    	PairDist aragaey2 = new PairDist(Ergintone,100);
    	adyacentesAragaey.add(aragaey1);
    	adyacentesAragaey.add(aragaey2);
    	
    	
    	//Icaedur
    	ArrayList <PairDist> adyacentesIcaedur = new ArrayList<PairDist>();
    	PairDist icaedur1 = new PairDist(Bulovoe,350);
    	PairDist icaedur2 = new PairDist(Vinizaile,100);
    	adyacentesIcaedur.add(icaedur1);
    	adyacentesIcaedur.add(icaedur2);
    	
    	//Bresol
    	ArrayList <PairDist> adyacentesBresol = new ArrayList<PairDist>();
    	PairDist bresol1 = new PairDist(Aragaey,150);
    	PairDist bresol2 = new PairDist(Vinizaile,400);
    	adyacentesBresol.add(bresol1);
    	adyacentesBresol.add(bresol2);
    	
    	//Vinizaile
    	ArrayList <PairDist> adyacentesVinizaile = new ArrayList<PairDist>();
    	PairDist vinizaile1 = new PairDist(Icaedur,100);
    	PairDist vinizaile2 = new PairDist(Peregaey,450);
    	PairDist vinizaile3 = new PairDist(Bresol,400);
    	PairDist vinizaile4 = new PairDist(Mixocu,300);
    	PairDist vinizaile5 = new PairDist(Cabe,200);
    	adyacentesVinizaile.add(vinizaile1);
    	adyacentesVinizaile.add(vinizaile2);
    	adyacentesVinizaile.add(vinizaile3);
    	adyacentesVinizaile.add(vinizaile4);
    	adyacentesVinizaile.add(vinizaile5);
    	
    	//Mixocu
    	ArrayList <PairDist> adyacentesMixocu = new ArrayList<PairDist>();
    	PairDist mixocu1 = new PairDist(Ase,200);
    	PairDist mixocu2 = new PairDist(Vinizaile,300);
    	adyacentesMixocu.add(mixocu1);
    	adyacentesMixocu.add(mixocu2);
    	
    	//Ase
    	ArrayList <PairDist> adyacentesAse = new ArrayList<PairDist>();
    	PairDist ase1 = new PairDist(Cenede,200);
    	PairDist ase2 = new PairDist(Mixocu,300);
    	adyacentesAse.add(ase1);
    	adyacentesAse.add(ase2);
    	
    	//Cabe
    	ArrayList <PairDist> adyacentesCabe = new ArrayList<PairDist>();
    	PairDist cabe1 = new PairDist(Vinizaile,200);
    	adyacentesCabe.add(cabe1);
    	
    	//Cenede
    	ArrayList <PairDist> adyacentesCenede = new ArrayList<PairDist>();
    	PairDist cenede1 = new PairDist(Ase,200);
    	adyacentesCenede.add(cenede1);
    	
    	//Generamos el Mapa
    	map.put(Ergintone, adyacentesErgintone);
    	map.put(Bulovoe, adyacentesBulovoe);
    	map.put(Peregaey, adyacentesPeregaey);
    	map.put(Aragaey, adyacentesAragaey);
    	map.put(Icaedur, adyacentesIcaedur);
    	map.put(Bresol, adyacentesBresol);
    	map.put(Vinizaile, adyacentesVinizaile);
    	map.put(Mixocu, adyacentesMixocu);
    	map.put(Ase, adyacentesAse);
    	map.put(Cabe, adyacentesCabe);
    	map.put(Cenede,  adyacentesCenede);
    }

    /**
     * This method returns the String representation of the agent state.
     */
    @Override
    public String toString() {
        String str = "";
        str+= "\nPosicion Actual: "+posicion;
        str+= "\nCapacidad Ocupada: "+capacidadOcupada;
        str+= "\nValor Obtenido: "+valorObtenido;
        str+= "\nCiudades Visitadas 1 vez: ";
        
        if(!visitadas1.isEmpty()){
        	for(String s : visitadas1){
            	str+= " "+s;
        	}
        }
        str+="\nCiudades Visitadas 2 veces: ";
        
        if(!visitadas2.isEmpty()){
        	for(String s : visitadas2){
            	str+= " "+s;
        	}
        } 
        str+= "\nObjetivo: "+posicionObjetivo;

        str+="\nDistancia Total Recorrida: "+distanciaRecorrida;

        return str;
    }

    /**
     * This method is used in the search process to verify if the node already
     * exists in the actual search.
     */
    @Override
    public boolean equals(Object obj) {
       
       ArqueologoState nuevo = (ArqueologoState) obj;
       String viejaPos = this.getPosicion();
       String nuevaPos = nuevo.getPosicion();
       Cofre viejoTes = this.getCofre(this.getPosicion());
       Cofre nuevoTes = nuevo.getCofre(nuevo.getPosicion());
       ArrayList<String> visitviejo1 = new ArrayList<String>();
       ArrayList<String> visitviejo2 = new ArrayList<String>();
       ArrayList<String> visitnuevo1 = new ArrayList<String>();
       ArrayList<String> visitnuevo2 = new ArrayList<String>();
       visitviejo1.addAll(this.getVisitadas1());
       visitnuevo1.addAll(nuevo.getVisitadas1());
       visitviejo2.addAll(this.getVisitadas2());
       visitviejo2.addAll(nuevo.getVisitadas2());
       double d1 = this.getDistanciaRecorrida();
       double d2 = nuevo.getDistanciaRecorrida();
       
       //distancia?
       if(nuevaPos.equals(viejaPos)){
    	   
    	   if(viejoTes==null && nuevoTes==null){
    		   return true;
    	   }
    	   else{
    		   if(viejoTes == null || nuevoTes == null){
    			   return false;
    		   }
    		   else{
    			   if(visitviejo1.equals(visitnuevo1) && visitviejo2.equals(visitnuevo2)){
    				   return true;
    			   }
    			   else
    			   return viejoTes.equals(nuevoTes);
    		   }
    	   }	
    	}
       else{
    	   return false;
       }
    }

    //TODO: Complete this section with agent-specific methods
    // The following methods are agent-specific:

     
     public void setposicion(String arg){
        posicion = arg;
     }
     public int costoViajar(String aldea){
    	 Collection<PairDist> p = this.map.get(this.posicion);
    	 for(PairDist d: p){
    		 if(d.getAldea().equals(aldea)){
    			 return d.getLongitud();
    		 }
    	 }
    	 return 0;
    	 
     }

	public String getPosicion() {
		return posicion;
	}

	public void setPosicion(String posicion) {
		this.posicion = posicion;
	}

	public HashMap<String, Collection<PairDist>> getMap() {
		return map;
	}

	public void setMap(HashMap<String, Collection<PairDist>> map) {
		this.map = map;
	}

	public HashMap<String, Cofre> getTesoro() {
		return tesoro;
	}

	public void setTesoro(HashMap<String, Cofre> tesoro) {
		this.tesoro = tesoro;
	}

	public double getCapacidadOcupada() {
		return capacidadOcupada;
	}

	public void setCapacidadOcupada(double capacidadOcupada) {
		this.capacidadOcupada = capacidadOcupada;
	}

	public ArrayList<String> getVisitadas1() {
		return visitadas1;
	}

	public void setVisitadas1(ArrayList<String> visitadas1) {
		this.visitadas1 = visitadas1;
	}

	public ArrayList<String> getVisitadas2() {
		return visitadas2;
	}

	public void setVisitadas2(ArrayList<String> visitadas2) {
		this.visitadas2 = visitadas2;
	}

    public String getPosicionObjetivo() {
		return posicionObjetivo;
	}

	public void setPosicionObjetivo(String posicionObjetivo) {
		this.posicionObjetivo = posicionObjetivo;
	}

	public static double getCapacidad() {
		return capacidad;
	}

    public double getDistanciaRecorrida() {
		return distanciaRecorrida;
	}

	public void setDistanciaRecorrida(double distanciaRecorrida) {
		this.distanciaRecorrida = distanciaRecorrida;
	}
	public Cofre getCofre(String aldea){
		Cofre t = this.tesoro.get(aldea);
		return t;
	}

	public double getValorObtenido() {
		return valorObtenido;
	}

	public void setValorObtenido(double valorObtenido) {
		this.valorObtenido = valorObtenido;
	}
	public int calcularDistancia(String inicio, String fin){
		Collection<PairDist> c = this.map.get(inicio);
		for(PairDist p : c){
			if(p.getAldea().equals(fin)){
				return p.getLongitud();
			}
		}
		return 0;
	}
	public double mejorOpcion(String a){
		Collection<PairDist> c = this.map.get(a);
		double min = 1000;
		String mejor = "";
			for(PairDist p : c){
				if(p.getLongitud()<min){
					mejor = p.getAldea();
					min = p.getLongitud();
				}
			
		}
			return min;
	}
	public ArrayList<String> getAdyacentes (String aldea){
		
		ArrayList<String> adyac = new ArrayList<String>();
		ArrayList <PairDist> p = new ArrayList<PairDist>();
		p.addAll(this.getMap().get(aldea));
			
		for(PairDist a: p)
		{
			adyac.add(a.getAldea());
		}
		
		return adyac;
	}


	
}

